@wonderwhy-er/desktop-commander 0.2.39 → 0.2.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +4 -2
  2. package/dist/handlers/filesystem-handlers.js +6 -0
  3. package/dist/server.js +2 -1
  4. package/dist/tools/filesystem.js +48 -14
  5. package/dist/types.d.ts +1 -0
  6. package/dist/ui/file-preview/preview-runtime.js +204 -153
  7. package/dist/ui/file-preview/src/{App.js → app.js} +0 -5
  8. package/dist/ui/file-preview/src/directory-controller.js +9 -2
  9. package/dist/ui/file-preview/src/file-type-handlers.js +20 -9
  10. package/dist/ui/file-preview/src/markdown/controller.d.ts +7 -1
  11. package/dist/ui/file-preview/src/markdown/controller.js +135 -16
  12. package/dist/ui/file-preview/src/markdown/editor.d.ts +97 -1
  13. package/dist/ui/file-preview/src/markdown/editor.js +814 -26
  14. package/dist/ui/file-preview/src/model.d.ts +2 -1
  15. package/dist/ui/file-preview/src/payload-utils.js +10 -1
  16. package/dist/utils/capture.js +1 -1
  17. package/dist/utils/feature-flags.d.ts +3 -0
  18. package/dist/utils/feature-flags.js +34 -5
  19. package/dist/utils/files/excel.js +26 -5
  20. package/dist/utils/toolHistory.d.ts +13 -0
  21. package/dist/utils/toolHistory.js +65 -0
  22. package/dist/version.d.ts +1 -1
  23. package/dist/version.js +1 -1
  24. package/package.json +7 -1
  25. package/dist/ui/config-editor/app.js +0 -840
  26. package/dist/ui/config-editor/array-modal.d.ts +0 -19
  27. package/dist/ui/config-editor/array-modal.js +0 -185
  28. package/dist/ui/config-editor/main.d.ts +0 -1
  29. package/dist/ui/config-editor/main.js +0 -2
  30. package/dist/ui/config-editor/src/App.d.ts +0 -43
  31. package/dist/ui/config-editor/src/components/layout.d.ts +0 -4
  32. package/dist/ui/config-editor/src/components/layout.js +0 -83
  33. package/dist/ui/config-editor/src/components/toolbar.d.ts +0 -1
  34. package/dist/ui/config-editor/src/components/toolbar.js +0 -21
  35. package/dist/ui/config-editor/src/config-values.d.ts +0 -6
  36. package/dist/ui/config-editor/src/config-values.js +0 -61
  37. package/dist/ui/config-editor/src/contracts.d.ts +0 -14
  38. package/dist/ui/config-editor/src/contracts.js +0 -3
  39. package/dist/ui/config-editor/src/directory-browser.d.ts +0 -6
  40. package/dist/ui/config-editor/src/directory-browser.js +0 -71
  41. package/dist/ui/config-editor/src/layout.d.ts +0 -5
  42. package/dist/ui/config-editor/src/layout.js +0 -90
  43. package/dist/ui/config-editor/src/parsing.d.ts +0 -5
  44. package/dist/ui/config-editor/src/parsing.js +0 -50
  45. package/dist/ui/config-editor/src/toolbar.d.ts +0 -1
  46. package/dist/ui/config-editor/src/toolbar.js +0 -18
  47. package/dist/ui/config-editor/src/types.d.ts +0 -17
  48. package/dist/ui/config-editor/src/types.js +0 -3
  49. package/dist/ui/config-editor/src/utils/config-values.d.ts +0 -9
  50. package/dist/ui/config-editor/src/utils/config-values.js +0 -61
  51. package/dist/ui/config-editor/src/utils/directory-browser.d.ts +0 -31
  52. package/dist/ui/config-editor/src/utils/directory-browser.js +0 -201
  53. package/dist/ui/config-editor/src/utils/parsing.d.ts +0 -8
  54. package/dist/ui/config-editor/src/utils/parsing.js +0 -50
  55. package/dist/ui/file-preview/app.d.ts +0 -8
  56. package/dist/ui/file-preview/app.js +0 -2020
  57. package/dist/ui/file-preview/components/code-viewer.d.ts +0 -6
  58. package/dist/ui/file-preview/components/code-viewer.js +0 -73
  59. package/dist/ui/file-preview/components/highlighting.d.ts +0 -2
  60. package/dist/ui/file-preview/components/highlighting.js +0 -54
  61. package/dist/ui/file-preview/components/html-renderer.d.ts +0 -5
  62. package/dist/ui/file-preview/components/html-renderer.js +0 -47
  63. package/dist/ui/file-preview/components/markdown-renderer.d.ts +0 -1
  64. package/dist/ui/file-preview/components/markdown-renderer.js +0 -67
  65. package/dist/ui/file-preview/components/toolbar.d.ts +0 -6
  66. package/dist/ui/file-preview/components/toolbar.js +0 -75
  67. package/dist/ui/file-preview/image-preview.d.ts +0 -3
  68. package/dist/ui/file-preview/image-preview.js +0 -21
  69. package/dist/ui/file-preview/main.d.ts +0 -1
  70. package/dist/ui/file-preview/main.js +0 -5
  71. package/dist/ui/file-preview/markdown/editor.d.ts +0 -36
  72. package/dist/ui/file-preview/markdown/editor.js +0 -643
  73. package/dist/ui/file-preview/markdown/linking.d.ts +0 -9
  74. package/dist/ui/file-preview/markdown/linking.js +0 -210
  75. package/dist/ui/file-preview/markdown/outline.d.ts +0 -7
  76. package/dist/ui/file-preview/markdown/outline.js +0 -40
  77. package/dist/ui/file-preview/markdown/preview.d.ts +0 -8
  78. package/dist/ui/file-preview/markdown/preview.js +0 -33
  79. package/dist/ui/file-preview/markdown/slugify.d.ts +0 -3
  80. package/dist/ui/file-preview/markdown/slugify.js +0 -31
  81. package/dist/ui/file-preview/markdown/toc.d.ts +0 -11
  82. package/dist/ui/file-preview/markdown/toc.js +0 -75
  83. package/dist/ui/file-preview/markdown/utils.d.ts +0 -1
  84. package/dist/ui/file-preview/markdown/utils.js +0 -15
  85. package/dist/ui/file-preview/markdown/workspace-controller.d.ts +0 -25
  86. package/dist/ui/file-preview/markdown/workspace-controller.js +0 -40
  87. package/dist/ui/file-preview/src/components/CodeViewer.d.ts +0 -6
  88. package/dist/ui/file-preview/src/components/CodeViewer.js +0 -60
  89. package/dist/ui/file-preview/src/components/HtmlRenderer.d.ts +0 -8
  90. package/dist/ui/file-preview/src/components/HtmlRenderer.js +0 -45
  91. package/dist/ui/file-preview/src/components/MarkdownRenderer.d.ts +0 -1
  92. package/dist/ui/file-preview/src/components/MarkdownRenderer.js +0 -15
  93. package/dist/ui/file-preview/src/components/Toolbar.d.ts +0 -6
  94. package/dist/ui/file-preview/src/components/Toolbar.js +0 -75
  95. package/dist/ui/file-preview/src/components/editor-toolbar.d.ts +0 -15
  96. package/dist/ui/file-preview/src/components/editor-toolbar.js +0 -384
  97. package/dist/ui/file-preview/src/components/markdown-editor.d.ts +0 -29
  98. package/dist/ui/file-preview/src/components/markdown-editor.js +0 -535
  99. package/dist/ui/file-preview/src/markdown/block-merge.d.ts +0 -25
  100. package/dist/ui/file-preview/src/markdown/block-merge.js +0 -86
  101. package/dist/ui/file-preview/src/markdown/link-modal.d.ts +0 -13
  102. package/dist/ui/file-preview/src/markdown/link-modal.js +0 -213
  103. package/dist/ui/file-preview/src/markdown/raw-editor.d.ts +0 -8
  104. package/dist/ui/file-preview/src/markdown/raw-editor.js +0 -61
  105. package/dist/ui/file-preview/src/markdown/selection-toolbar.d.ts +0 -14
  106. package/dist/ui/file-preview/src/markdown/selection-toolbar.js +0 -128
  107. package/dist/ui/file-preview/src/markdown/toc.d.ts +0 -11
  108. package/dist/ui/file-preview/src/markdown/toc.js +0 -75
  109. package/dist/ui/file-preview/src/markdown-workspace/editor.d.ts +0 -36
  110. package/dist/ui/file-preview/src/markdown-workspace/editor.js +0 -643
  111. package/dist/ui/file-preview/src/markdown-workspace/linking.d.ts +0 -9
  112. package/dist/ui/file-preview/src/markdown-workspace/linking.js +0 -210
  113. package/dist/ui/file-preview/src/markdown-workspace/outline.d.ts +0 -7
  114. package/dist/ui/file-preview/src/markdown-workspace/outline.js +0 -40
  115. package/dist/ui/file-preview/src/markdown-workspace/preview.d.ts +0 -8
  116. package/dist/ui/file-preview/src/markdown-workspace/preview.js +0 -33
  117. package/dist/ui/file-preview/src/markdown-workspace/slugify.d.ts +0 -3
  118. package/dist/ui/file-preview/src/markdown-workspace/slugify.js +0 -31
  119. package/dist/ui/file-preview/src/markdown-workspace/toc.d.ts +0 -11
  120. package/dist/ui/file-preview/src/markdown-workspace/toc.js +0 -75
  121. package/dist/ui/file-preview/src/markdown-workspace/utils.d.ts +0 -1
  122. package/dist/ui/file-preview/src/markdown-workspace/utils.js +0 -15
  123. package/dist/ui/file-preview/src/markdown-workspace/workspace-controller.d.ts +0 -25
  124. package/dist/ui/file-preview/src/markdown-workspace/workspace-controller.js +0 -40
  125. package/dist/ui/file-preview/types.d.ts +0 -1
  126. package/dist/ui/file-preview/types.js +0 -1
  127. package/dist/ui/server-integration.d.ts +0 -13
  128. package/dist/ui/server-integration.js +0 -31
  129. package/dist/ui/shared/ToolHeader.d.ts +0 -9
  130. package/dist/ui/shared/ToolHeader.js +0 -29
  131. package/dist/ui/shared/app-bootstrap.d.ts +0 -9
  132. package/dist/ui/shared/app-bootstrap.js +0 -15
  133. package/dist/ui/shared/guards.d.ts +0 -1
  134. package/dist/ui/shared/guards.js +0 -3
  135. package/dist/ui/shared/host-lifecycle.d.ts +0 -17
  136. package/dist/ui/shared/host-lifecycle.js +0 -41
  137. package/dist/ui/shared/rpc-client.d.ts +0 -14
  138. package/dist/ui/shared/rpc-client.js +0 -72
  139. package/dist/ui/shared/theme-adaptation.d.ts +0 -10
  140. package/dist/ui/shared/theme-adaptation.js +0 -118
  141. package/dist/ui/shared/tool-header.d.ts +0 -9
  142. package/dist/ui/shared/tool-header.js +0 -25
  143. package/dist/utils/ui-call-context.d.ts +0 -8
  144. package/dist/utils/ui-call-context.js +0 -72
  145. /package/dist/ui/config-editor/{app.d.ts → src/app.d.ts} +0 -0
  146. /package/dist/ui/config-editor/src/{App.js → app.js} +0 -0
  147. /package/dist/ui/file-preview/src/{App.d.ts → app.d.ts} +0 -0
package/README.md CHANGED
@@ -335,9 +335,11 @@ Desktop Commander works with any MCP-compatible client. The standard JSON config
335
335
  Add this to your client's MCP configuration file at the locations below:
336
336
 
337
337
  <details>
338
- <summary><b>Cursor</b></summary>
338
+ <summary><b>Cursor</b></summary><br>
339
339
 
340
- [Install MCP Server in Cursor](https://cursor.directory/mcp/desktop-commander-mcp)
340
+ [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=desktop-commander&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkB3b25kZXJ3aHktZXIvZGVza3RvcC1jb21tYW5kZXJAbGF0ZXN0Il19)
341
+
342
+ [View MCP Server in Directory](https://cursor.directory/mcp/desktop-commander-mcp)
341
343
 
342
344
  Or add manually to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` in your project folder (project-specific).
343
345
 
@@ -99,6 +99,10 @@ export async function handleReadFile(args) {
99
99
  fileName: path.basename(resolvedFilePath),
100
100
  filePath: resolvedFilePath,
101
101
  fileType: 'unsupported',
102
+ content: pdfContent
103
+ .filter((item) => item.type === "text")
104
+ .map((item) => item.text)
105
+ .join("\n"),
102
106
  },
103
107
  };
104
108
  }
@@ -121,6 +125,7 @@ export async function handleReadFile(args) {
121
125
  fileName: path.basename(resolvedFilePath),
122
126
  filePath: resolvedFilePath,
123
127
  fileType: 'image',
128
+ content: imageData,
124
129
  imageData,
125
130
  mimeType: fileResult.mimeType
126
131
  }
@@ -140,6 +145,7 @@ export async function handleReadFile(args) {
140
145
  fileName: path.basename(resolvedFilePath),
141
146
  filePath: resolvedFilePath,
142
147
  fileType,
148
+ content: textContent,
143
149
  },
144
150
  };
145
151
  }
package/dist/server.js CHANGED
@@ -445,6 +445,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
445
445
  [FILE] src/tools/filesystem.ts
446
446
 
447
447
  If a directory cannot be accessed, it will show [DENIED] instead.
448
+ If a path does not exist, it will show [NOT_FOUND] instead.
448
449
  Only works within allowed directories.
449
450
 
450
451
  ${PATH_GUIDANCE}
@@ -1092,7 +1093,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1092
1093
  const startTime = Date.now();
1093
1094
  try {
1094
1095
  // Prepare telemetry data - add config key for set_config_value
1095
- const telemetryData = { name };
1096
+ const telemetryData = { tool_name: name };
1096
1097
  // Extract metadata from _meta field if present
1097
1098
  const metadata = request.params._meta;
1098
1099
  if (metadata && typeof metadata === 'object') {
@@ -220,6 +220,38 @@ export async function validatePath(requestedPath) {
220
220
  });
221
221
  throw new Error(`Failed to resolve symlink for path: ${absoluteOriginal}. Error: ${err.message}`);
222
222
  }
223
+ // SECURITY FIX: When the full path doesn't exist (e.g., writing a new file),
224
+ // resolve the parent directory to detect symlinks in the path chain.
225
+ // Without this, an attacker could create a symlink inside an allowed directory
226
+ // pointing to a restricted location, then write to a non-existent file through
227
+ // that symlink — bypassing the directory restriction check.
228
+ try {
229
+ const parentDir = path.dirname(absoluteOriginal);
230
+ const resolvedParent = await fs.realpath(parentDir, { encoding: 'utf8' });
231
+ const basename = path.basename(absoluteOriginal);
232
+ resolvedRealPath = path.join(resolvedParent, basename);
233
+ }
234
+ catch {
235
+ // Parent also doesn't exist — walk up the tree to find
236
+ // the deepest existing ancestor and resolve it
237
+ let current = absoluteOriginal;
238
+ let remaining = [];
239
+ while (true) {
240
+ const parent = path.dirname(current);
241
+ if (parent === current)
242
+ break; // reached filesystem root
243
+ remaining.unshift(path.basename(current));
244
+ current = parent;
245
+ try {
246
+ const resolvedAncestor = await fs.realpath(current, { encoding: 'utf8' });
247
+ resolvedRealPath = path.join(resolvedAncestor, ...remaining);
248
+ break;
249
+ }
250
+ catch {
251
+ // keep walking up
252
+ }
253
+ }
254
+ }
223
255
  }
224
256
  const pathForNextCheck = resolvedRealPath ?? absoluteOriginal;
225
257
  // Check if path is allowed
@@ -230,25 +262,25 @@ export async function validatePath(requestedPath) {
230
262
  });
231
263
  throw new Error(`Path not allowed: ${requestedPath}. Must be within one of these directories: ${(await getAllowedDirs()).join(', ')}`);
232
264
  }
265
+ // SECURITY: Always return the resolved path (with symlinks resolved) so that
266
+ // all subsequent file operations (read, write, mkdir, etc.) operate on the
267
+ // canonical target, not on a symlink that could point outside allowed directories.
268
+ // pathForNextCheck already holds resolvedRealPath ?? absoluteOriginal from above.
233
269
  // Check if path exists
234
270
  try {
235
271
  // fs.stat() will automatically follow symlinks, so we get existence info
236
- const stats = await fs.stat(absoluteOriginal);
237
- // If path exists, resolve any symlinks
238
- if (resolvedRealPath) {
239
- return resolvedRealPath;
240
- }
241
- return absoluteOriginal;
272
+ await fs.stat(pathForNextCheck);
273
+ return pathForNextCheck;
242
274
  }
243
275
  catch (error) {
244
276
  // Path doesn't exist - validate parent directories
245
- if (await validateParentDirectories(absoluteOriginal)) {
246
- // Return the path if a valid parent exists
277
+ if (await validateParentDirectories(pathForNextCheck)) {
278
+ // Return the resolved path if a valid parent exists
247
279
  // This will be used for folder creation and many other file operations
248
- return absoluteOriginal;
280
+ return pathForNextCheck;
249
281
  }
250
- // If no valid parent found, return the absolute path anyway
251
- return absoluteOriginal;
282
+ // If no valid parent found, return the resolved path anyway
283
+ return pathForNextCheck;
252
284
  }
253
285
  };
254
286
  // Execute with timeout
@@ -573,9 +605,11 @@ export async function listDirectory(dirPath, depth = 2) {
573
605
  catch (error) {
574
606
  const err = error;
575
607
  const displayPath = relativePath || path.basename(currentPath);
576
- // Keep [DENIED] prefix so UI parser regex still matches.
577
- // Append a hint for permission/timeout errors so user gets context.
578
- if (err.code === 'EPERM' || err.code === 'EACCES' || err.code === 'ETIMEDOUT') {
608
+ // Distinguish "not found" from "permission denied" so AI and UI get accurate info.
609
+ if (err.code === 'ENOENT') {
610
+ results.push(`[NOT_FOUND] ${displayPath} path does not exist`);
611
+ }
612
+ else if (err.code === 'EPERM' || err.code === 'EACCES' || err.code === 'ETIMEDOUT') {
579
613
  results.push(`[DENIED] ${displayPath} — not accessible (permission denied, cloud-only file, or Full Disk Access not granted)`);
580
614
  }
581
615
  else {
package/dist/types.d.ts CHANGED
@@ -65,6 +65,7 @@ export interface FilePreviewStructuredContent {
65
65
  fileName: string;
66
66
  filePath: string;
67
67
  fileType: PreviewFileType;
68
+ content?: string;
68
69
  imageData?: string;
69
70
  mimeType?: string;
70
71
  }